package com.medusa.aps.business.modules.modeling.mp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.medusa.aps.business.model.constant.RedisConstants;
import com.medusa.aps.business.model.exception.BusinessErrorCode;
import com.medusa.aps.business.model.pagination.Page;
import com.medusa.aps.business.modules.basic.model.output.MaterialChooseVO;
import com.medusa.aps.business.modules.basic.mp.entity.Material;
import com.medusa.aps.business.modules.basic.mp.service.MaterialService;
import com.medusa.aps.business.modules.modeling.model.input.*;
import com.medusa.aps.business.modules.modeling.model.output.*;
import com.medusa.aps.business.modules.modeling.mp.entity.*;
import com.medusa.aps.business.modules.modeling.mp.mapper.ProcessRouteMapper;
import com.medusa.aps.business.modules.modeling.mp.service.*;
import com.medusa.aps.business.common.redis.annotation.Redisson;
import com.medusa.aps.business.global.model.exception.GlobalException;
import io.vavr.Tuple;
import io.vavr.Tuple2;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 工艺路线服务实现类
 *
 * @author yuxh
 * @since 2023-08-14 17:37:49
 */
@Slf4j
@Service("processRouteService")
public class ProcessRouteServiceImpl extends ServiceImpl<ProcessRouteMapper, ProcessRoute> implements ProcessRouteService {
    @Resource
    private TechnologicalProcessService technologicalProcessService;
    @Resource
    private MaterialService materialService;
    @Resource
    private ProcessEquipmentService processEquipmentService;
    @Resource
    private WorkingProcedureEquipmentService workingProcedureEquipmentService;
    @Resource
    private WorkingProcedureAuxiliaryService workingProcedureAuxiliaryService;
    @Resource
    private WorkingProcedureService workingProcedureService;

    /**
     * 分页查询所有数据
     *
     * @param page              分页参数
     * @param processRouteParam 查询实体
     * @return 所有数据
     */
    @Override
    public Page<ProcessRouteVO> selectPage(Page<ProcessRoute> page, ProcessRouteParam processRouteParam) {
        Page<ProcessRoute> routePage = getPage(page, processRouteParam);
        if (CollUtil.isEmpty(routePage.getRecords())) {
            return new Page<>(routePage.getCurrent(), routePage.getSize());
        }
        return new Page<>(routePage.getCurrent(), routePage.getSize(), routePage.getTotal(),
                handlerProcessRoutes(routePage.getRecords()));
    }

    /**
     * 查询工艺路线详情
     *
     * @param param 查询参数
     * @return 工艺路线详情
     */
    @Override
    public ProcessRouteDetailVO detail(ProcessDetailParam param) {
        ProcessRoute processRoute = lambdaQuery()
                .select(ProcessRoute::getId, ProcessRoute::getProcessRouteCode, ProcessRoute::getProcessRouteName,
                        ProcessRoute::getMaterialId, ProcessRoute::getMaterialCode, ProcessRoute::getRemarks,
                        ProcessRoute::getProcessRemark, ProcessRoute::getProcessRouteDesc)
                .eq(param.getProcessId() != null, ProcessRoute::getId, param.getProcessId())
                .eq(StrUtil.isNotEmpty(param.getMaterialCode()), ProcessRoute::getMaterialCode, param.getMaterialCode())
                .one();
        if (BeanUtil.isEmpty(processRoute)) {
            throw BusinessErrorCode.DATA_IS_EMPTY.exception();
        }
        return processRoute.toProcessRouteDetailVO()
                .setTechnologicalProcess(technologicalProcessService.getTechnologicalProcess(processRoute.getId()));
    }

    /**
     * 需求订单查询工艺路线详情
     *
     * @param page         分页
     * @param materialCode 物料编码
     * @return 订单查询工艺路线详情
     */
    @Override
    public Page<OrderTechnologicalProcessVO> orderTechnologicalProcess(Page<TechnologicalProcessVO> page, String materialCode) {
        Page<TechnologicalProcessVO> technologicalProcessPage = technologicalProcessService.getTechnologicalProcessPage(page,
                materialCode);
        List<TechnologicalProcessVO> records = technologicalProcessPage.getRecords();
        if (CollUtil.isEmpty(records)) {
            return new Page<>();
        }
        List<OrderTechnologicalProcessVO> result = new ArrayList<>();
        //为了前端表格展示方便，子项与父项同层
        for (TechnologicalProcessVO technologicalProcess : records) {
            OrderTechnologicalProcessVO technologicalProcessVO = technologicalProcess.toTechnologicalProcessVO();
            List<ProcessEquipmentVO> processEquipment = technologicalProcess.getProcessEquipments();
            processEquipment.get(0).toOrderTechnologicalProcessVO(technologicalProcessVO, result);
            for (int i = 1; i < processEquipment.size(); i++) {
                processEquipment.get(i)
                        .toOrderTechnologicalProcessVO(new OrderTechnologicalProcessVO(), result);
            }
        }
        return new Page<>(page.getCurrent(), page.getSize(), technologicalProcessPage.getTotal(), result);
    }

    /**
     * 工艺路线选择物料
     *
     * @param chooseMaterialRouteParam 搜索参数
     * @return 物料信息
     */
    @Override
    public Page<MaterialChooseVO> chooseMaterial(ChooseMaterialRouteParam chooseMaterialRouteParam) {
        return baseMapper.chooseMaterial(chooseMaterialRouteParam, new Page<>(chooseMaterialRouteParam.getCurrent(), chooseMaterialRouteParam.getSize()));
    }

    /**
     * 保存工艺路线
     *
     * @param processRouteDTO 保存的数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Redisson(name = RedisConstants.PROCESS_ROUTE_LOCK_KEY, waitTime = 1)
    @Redisson(name = RedisConstants.WORKING_PROCEDURE_LOCK_KEY, waitTime = 1)
    public void saveProcessRoute(ProcessRouteDTO processRouteDTO) {
        ProcessRoute processRoute = processRouteDTO.toProcessRoute();
        lambdaQuery()
                .select(ProcessRoute::getProcessRouteCode)
                .eq(ProcessRoute::getProcessRouteCode, processRouteDTO.getProcessRouteCode())
                .oneOpt()
                .ifPresent(item -> {
                    throw new GlobalException(BusinessErrorCode.DATA_IS_USED.getCode(), StrUtil.format("工艺路线编码【{}】系统已存在", processRouteDTO.getProcessRouteCode()));
                });

        lambdaQuery()
                .select(ProcessRoute::getMaterialCode)
                .eq(ProcessRoute::getMaterialCode, processRouteDTO.getMaterialCode())
                .oneOpt()
                .ifPresent(item -> {
                    throw new GlobalException(BusinessErrorCode.DATA_IS_USED.getCode(), StrUtil.format("物料编码【{}】系统已使用", processRouteDTO.getMaterialCode()));
                });

        materialService.lambdaQuery()
                .select(Material::getId)
                .eq(Material::getId, processRoute.getMaterialId())
                .eq(Material::getMaterialCode, processRoute.getMaterialCode())
                .oneOpt()
                .orElseThrow(() -> new GlobalException(BusinessErrorCode.DATA_IS_EMPTY.getCode(), "物料不存在"));
        boolean flag = save(processRoute);
        if (!flag) {
            throw new GlobalException(BusinessErrorCode.SYSTEM_ERROR.getCode(), "工艺路线新增失败");
        }
        saveTechnologicalProcess(processRouteDTO, processRoute);
    }

    private void saveTechnologicalProcess(ProcessRouteDTO processRouteDTO, ProcessRoute processRoute) {
        List<TechnologicalProcessDTO> technologicalProcess = processRouteDTO.getTechnologicalProcess();
        List<TechnologicalProcess> technologicalProcesses = new ArrayList<>();
        for (int i = 0; i < technologicalProcess.size(); i++) {
            TechnologicalProcessDTO processDTO = technologicalProcess.get(i);
            processDTO.setProcessNumber(i + 1);
            TechnologicalProcess process = processDTO.toTechnologicalProcess(processRoute.getId(), processRoute.getMaterialId(), processRoute.getMaterialCode(), processDTO.getProcessNumber());
            technologicalProcesses.add(process);
        }
        boolean batch = technologicalProcessService.saveBatch(technologicalProcesses);
        if (!batch) {
            throw new GlobalException(BusinessErrorCode.SYSTEM_ERROR.getCode(), "工艺工序绑定关系新增失败");
        }
        Map<Integer, Integer> technologicalMap = technologicalProcesses.stream()
                .collect(Collectors.toMap(TechnologicalProcess::getProcessNumber, TechnologicalProcess::getId));
        Map<Integer, TechnologicalProcessDTO> map = technologicalProcess.stream()
                .collect(Collectors.toMap(TechnologicalProcessDTO::getProcessNumber, item -> item));
        List<ProcessEquipment> processEquipmentList = new ArrayList<>();
        map.forEach((key, value) -> {
            List<ProcessEquipmentDTO> processEquipments = value.getProcessEquipments();
            processEquipments.forEach(processEquipmentDTO ->
                    processEquipmentList.add(
                            processEquipmentDTO.toProcessEquipment(
                                    technologicalMap.get(key),
                                    value.getProcessId(),
                                    processRoute.getId(),
                                    processRoute.getMaterialId(),
                                    processRoute.getMaterialCode())
                    )
            );
        });
        boolean saveBatch = processEquipmentService.saveBatch(processEquipmentList);
        if (!saveBatch) {
            throw new GlobalException(BusinessErrorCode.SYSTEM_ERROR.getCode(), "工艺工序设备绑定新增失败");
        }
    }

    /**
     * 编辑工艺路线
     *
     * @param processRouteDTO 编辑的数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Redisson(name = RedisConstants.PROCESS_ROUTE_LOCK_KEY, waitTime = 1)
    @Redisson(name = RedisConstants.WORKING_PROCEDURE_LOCK_KEY, waitTime = 1)
    public void updateProcessRoute(ProcessRouteDTO processRouteDTO) {
        ProcessRouteDetailVO detailVO = validProcessRoute(processRouteDTO);
        lambdaUpdate().eq(ProcessRoute::getId, detailVO.getId())
                .set(ProcessRoute::getProcessRouteName, processRouteDTO.getProcessRouteName())
                .set(ProcessRoute::getMaterialId, processRouteDTO.getMaterialId())
                .set(ProcessRoute::getMaterialCode, processRouteDTO.getMaterialCode())
                .set(ProcessRoute::getProcessRouteDesc, processRouteDTO.getProcessRouteDesc())
                .set(ProcessRoute::getProcessRemark, false)
                .set(ProcessRoute::getRemarks, processRouteDTO.getRemarks())
                .update();
        deleteTechnological(List.of(processRouteDTO.getProcessRouteId()));
        ProcessRoute processRoute = new ProcessRoute()
                .setId(processRouteDTO.getProcessRouteId())
                .setMaterialId(processRouteDTO.getMaterialId())
                .setMaterialCode(processRouteDTO.getMaterialCode());
        saveTechnologicalProcess(processRouteDTO, processRoute);
    }

    /**
     * 校验工艺路线
     *
     * @param processRouteDTO 工艺路线参数
     */
    private ProcessRouteDetailVO validProcessRoute(ProcessRouteDTO processRouteDTO) {
        ProcessRouteDetailVO detailVO = Optional.ofNullable(detail(new ProcessDetailParam().setProcessId(processRouteDTO.getProcessRouteId())))
                .orElseThrow(() -> new GlobalException(BusinessErrorCode.DATA_IS_EMPTY.getCode(), "工艺路线不存在"));
        if (!processRouteDTO.getProcessRouteCode().equals(detailVO.getProcessRouteCode())) {
            throw new GlobalException(BusinessErrorCode.PARAMETER_ERROR.getCode(), "工艺路线编码不允许编辑");
        }

        lambdaQuery()
                .select(ProcessRoute::getId)
                .eq(ProcessRoute::getMaterialCode, processRouteDTO.getMaterialCode())
                .ne(ProcessRoute::getId, processRouteDTO.getProcessRouteId())
                .oneOpt()
                .ifPresent(
                        processRoutes -> {
                            throw new GlobalException(BusinessErrorCode.DATA_IS_USED.getCode(), StrUtil.format("物料编码:{},已被使用", processRouteDTO.getMaterialCode()));
                        });
        lambdaQuery().select(ProcessRoute::getProcessRouteCode)
                .eq(ProcessRoute::getProcessRouteCode, processRouteDTO.getProcessRouteCode())
                .ne(ProcessRoute::getId, processRouteDTO.getProcessRouteId())
                .oneOpt()
                .ifPresent(item -> {
                    throw new GlobalException(BusinessErrorCode.DATA_IS_USED.getCode(), StrUtil.format("工艺路线编码:{},已被使用", processRouteDTO.getProcessRouteCode()));
                });
        materialService.lambdaQuery()
                .select(Material::getId)
                .eq(Material::getId, processRouteDTO.getMaterialId())
                .eq(Material::getMaterialCode, processRouteDTO.getMaterialCode())
                .oneOpt()
                .orElseThrow(() -> new GlobalException(BusinessErrorCode.DATA_IS_EMPTY.getCode(), StrUtil.format("物料:{},不存在", processRouteDTO.getMaterialCode())));

        return detailVO;
    }

    /**
     * 根据id删除工艺路线
     *
     * @param processRouteIds 工艺路线id集合
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Redisson(name = RedisConstants.PROCESS_ROUTE_LOCK_KEY, waitTime = 1)
    public void deleteProcessRouteByIds(List<Integer> processRouteIds) {
        validProcessRouteIsDelete(processRouteIds);
        deleteProcessRoute(processRouteIds);
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteProcessRoute(List<Integer> processRouteIds) {
        boolean processFlag = removeByIds(processRouteIds);
        if (!processFlag) {
            throw new GlobalException(BusinessErrorCode.SYSTEM_ERROR.getCode(), "工艺路线删除失败");
        }
        deleteTechnological(processRouteIds);
    }

    /**
     * 删除工艺路线下的工序
     *
     * @param processRouteIds 工艺路线id集合
     */
    private void deleteTechnological(List<Integer> processRouteIds) {
        boolean technologicalFlag = technologicalProcessService.lambdaUpdate()
                .in(TechnologicalProcess::getProcessRouteId, processRouteIds)
                .remove();
        if (!technologicalFlag) {
            throw new GlobalException(BusinessErrorCode.SYSTEM_ERROR.getCode(), "工艺工序绑定关系删除失败");
        }
        boolean equipmentFlag = processEquipmentService.lambdaUpdate()
                .in(ProcessEquipment::getProcessRouteId, processRouteIds)
                .remove();
        if (!equipmentFlag) {
            throw new GlobalException(BusinessErrorCode.SYSTEM_ERROR.getCode(), "工艺工序设备关系绑定失败");
        }
    }

    private void validProcessRouteIsDelete(List<Integer> processRouteIds) {
        List<ProcessRoute> processRoutes = lambdaQuery()
                .select(ProcessRoute::getId, ProcessRoute::getMaterialCode, ProcessRoute::getProcessRouteCode, ProcessRoute::getProcessRouteName)
                .in(ProcessRoute::getId, processRouteIds)
                .list();
        if (CollUtil.isEmpty(processRoutes) || processRoutes.size() != processRouteIds.size()) {
            throw new GlobalException(BusinessErrorCode.DATA_IS_EMPTY.getCode(), "工艺路线不存在");
        }
    }

    private List<ProcessRouteVO> handlerProcessRoutes(List<ProcessRoute> processRoutes) {
        Map<Integer, List<TechnologicalProcess>> technologicalMap = handlerTechnologicalMap(processRoutes);
        return processRoutes.stream().map(item ->
                item.toProcessRouteVO()
                        .setProcessIdCollection(StrUtil.join(StrUtil.COMMA,
                                technologicalMap.get(item.getId()).stream()
                                        .map(TechnologicalProcess::getProcessCode).collect(Collectors.toList())))
                        .setProcessRoute(StrUtil.join(">",
                                technologicalMap.get(item.getId()).stream()
                                        .map(TechnologicalProcess::getProcessName).collect(Collectors.toList())))
        ).collect(Collectors.toList());
    }

    private Map<Integer, List<TechnologicalProcess>> handlerTechnologicalMap(List<ProcessRoute> processRoutes) {
        Set<Integer> processRouteIds = processRoutes.stream().map(ProcessRoute::getId).collect(Collectors.toSet());
        List<TechnologicalProcess> processList = technologicalProcessService.lambdaQuery()
                .select(TechnologicalProcess::getId, TechnologicalProcess::getProcessName, TechnologicalProcess::getProcessCode,
                        TechnologicalProcess::getProcessRouteId, TechnologicalProcess::getProcessNumber)
                .in(TechnologicalProcess::getProcessRouteId, processRouteIds)
                .list();
        return processList.stream()
                .collect(Collectors.groupingBy(TechnologicalProcess::getProcessRouteId,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                processes -> processes.stream()
                                        .sorted(Comparator.comparing(TechnologicalProcess::getProcessNumber))
                                        .collect(Collectors.toList()))
                ));
    }

    private Page<ProcessRoute> getPage(Page<ProcessRoute> page, ProcessRouteParam processRouteParam) {
        return lambdaQuery()
                .select(ProcessRoute::getId, ProcessRoute::getProcessRouteCode, ProcessRoute::getProcessRouteName,
                        ProcessRoute::getProcessRouteDesc, ProcessRoute::getCreator,
                        ProcessRoute::getMaterialCode, ProcessRoute::getRemarks,
                        ProcessRoute::getProcessRemark, ProcessRoute::getCreateTime)
                .eq(processRouteParam.getProcessRemark() != null, ProcessRoute::getProcessRemark, processRouteParam.getProcessRemark())
                .in(CollUtil.isNotEmpty(processRouteParam.getIds()), ProcessRoute::getId, processRouteParam.getIds())
                .like(StrUtil.isNotEmpty(processRouteParam.getProcessRouteCode()), ProcessRoute::getProcessRouteCode,
                        processRouteParam.getProcessRouteCode())
                .like(StrUtil.isNotEmpty(processRouteParam.getProcessRouteName()), ProcessRoute::getProcessRouteName,
                        processRouteParam.getProcessRouteName())
                .like(StrUtil.isNotEmpty(processRouteParam.getCreator()), ProcessRoute::getCreator,
                        processRouteParam.getCreator())
                .like(StrUtil.isNotEmpty(processRouteParam.getMaterialCode()), ProcessRoute::getMaterialCode,
                        processRouteParam.getMaterialCode())
                .between(processRouteParam.getCreateTime().getStartTime() != null && processRouteParam.getCreateTime().getEndTime() != null,
                        ProcessRoute::getCreateTime,
                        processRouteParam.getCreateTime().getStartTime(),
                        processRouteParam.getCreateTime().getEndTime())
                .orderByDesc(ProcessRoute::getCreateTime)
                .page(page);
    }

    /**
     * 处理使用这道工序的工艺路线
     *
     * @param workingProcedureId           工序的id
     * @param equipmentAndAuxiliaryKeyList 设备与辅助资源键值对
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editeProcessWorkingProcedure(Integer workingProcedureId,
                                             Map<Long, Set<Integer>> equipmentAndAuxiliaryKeyList) {
        List<ProcessEquipment> processEquipments = processEquipmentService.lambdaQuery()
                .eq(ProcessEquipment::getProcessId, workingProcedureId)
                .list();
        if (CollUtil.isEmpty(processEquipments)) {
            return;
        }
        //查询所有使用这道工序设备与辅助资源的工艺路线数据
        Set<Integer> processRouteIds = processEquipments.stream().map(ProcessEquipment::getProcessRouteId).collect(Collectors.toSet());
        if (CollUtil.isEmpty(processRouteIds)) {
            return;
        }

        //工艺路线对应的所有设备与辅助资源数据
        List<ProcessRouteSimpleVO> processRouteSimple = baseMapper.processRouteSimple(processRouteIds);

        Map<Integer, Map<Integer, Map<Long, Set<Integer>>>> optimizedResult = processRouteSimple.stream().collect(Collectors.toMap(
                ProcessRouteSimpleVO::getProcessRouteId,
                processRoute ->
                        processRoute.getProcedures().stream()
                                .collect(Collectors.toMap(ProcedureVO::getWorkingProcedureId,
                                        value ->
                                                value.getProcedureEquipmentAndAuxiliaries().stream()
                                                        .collect(Collectors.toMap(ProcedureEquipmentAndAuxiliaryVO::getEquipmentId, ProcedureEquipmentAndAuxiliaryVO::getAuxiliaryIds))
                                ))
        ));

        List<ProcessEquipment> equipmentList = processEquipmentService.lambdaQuery()
                .in(ProcessEquipment::getProcessRouteId, processRouteIds)
                .list();

        Set<Integer> workingProcedureIds = equipmentList.stream()
                .map(ProcessEquipment::getProcessId)
                .filter(item -> !item.equals(workingProcedureId))
                .collect(Collectors.toSet());

        List<ProcedureVO> workingProcedureEquipments = new ArrayList<>();
        if (CollUtil.isNotEmpty(workingProcedureIds)) {
            workingProcedureEquipments = workingProcedureService.selectWorkingProcedureBatch(workingProcedureIds);
        }
        //工序id 设备id 辅助资源id
        Map<Integer, Map<Long, Set<Integer>>> map = workingProcedureEquipments.stream()
                .collect(Collectors.toMap(ProcedureVO::getWorkingProcedureId,
                        value ->
                                value.getProcedureEquipmentAndAuxiliaries().stream()
                                        .collect(Collectors.toMap(ProcedureEquipmentAndAuxiliaryVO::getEquipmentId, ProcedureEquipmentAndAuxiliaryVO::getAuxiliaryIds))
                ));

        map.put(workingProcedureId, equipmentAndAuxiliaryKeyList);
        Set<Integer> change = new HashSet<>();
        for (Map.Entry<Integer, Map<Integer, Map<Long, Set<Integer>>>> routeEntry : optimizedResult.entrySet()) {
            Integer routeId = routeEntry.getKey();
            //工序对应设备与辅助资源
            for (Map.Entry<Integer, Map<Long, Set<Integer>>> procedureEntry : routeEntry.getValue().entrySet()) {
                Integer procedureId = procedureEntry.getKey();
                if (!procedureEntry.getValue().equals(map.get(procedureId))) {
                    change.add(routeId);
                    break;
                }
            }
        }
        Set<Integer> all = optimizedResult.keySet();
        //没有变化的
        Collection<Integer> invariant = CollUtil.subtract(all, change);
        //变化的
        if (CollUtil.isNotEmpty(change)) {
            lambdaUpdate()
                    .set(ProcessRoute::getProcessRemark, true)
                    .in(ProcessRoute::getId, change)
                    .update();
        }
        if (CollUtil.isNotEmpty(invariant)) {
            lambdaUpdate()
                    .set(ProcessRoute::getProcessRemark, false)
                    .in(ProcessRoute::getId, invariant)
                    .update();
        }

    }

    /**
     * 工序变化之后的工艺路线详情
     *
     * @param id 工艺路线id
     * @return 工艺路线详情
     */
    @Override
    public ProcessRouteDetailVO detailChange(Integer id) {
        ProcessRouteDetailVO detail = detail(new ProcessDetailParam().setProcessId(id));
        if (!detail.getProcessRemark()) {
            return detail;
        }
        List<TechnologicalProcessVO> technologicalProcess = detail.getTechnologicalProcess();
        Set<Integer> processIds = technologicalProcess.stream().map(TechnologicalProcessVO::getProcessId).collect(Collectors.toSet());
        Map<Integer, List<WorkingProcedureEquipment>> workingProcedureEquipmentMap = workingProcedureEquipmentService.lambdaQuery()
                .in(WorkingProcedureEquipment::getWorkingProcedureId, processIds)
                .list().stream().collect(Collectors.groupingBy(WorkingProcedureEquipment::getWorkingProcedureId));


        Map<Integer, List<WorkingProcedureAuxiliary>> workingProcedureAuxiliaryMap = workingProcedureAuxiliaryService.lambdaQuery()
                .in(WorkingProcedureAuxiliary::getWorkingProcedureId, processIds)
                .list().stream().collect(Collectors.groupingBy(WorkingProcedureAuxiliary::getWorkingProcedureId));
        //遍历每道工序
        for (TechnologicalProcessVO process : technologicalProcess) {
            List<ProcessEquipmentVO> processEquipments = process.getProcessEquipments();
            Map<Integer, WorkingProcedureEquipment> equipmentGroupIdMap = workingProcedureEquipmentMap.get(process.getProcessId()).stream().collect(Collectors.toMap(WorkingProcedureEquipment::getId, value -> value));
            Map<Integer, List<WorkingProcedureAuxiliary>> equipmentIdAuxiliaryMap = ListUtil.toList(workingProcedureAuxiliaryMap.get(process.getProcessId())).stream().collect(Collectors.groupingBy(WorkingProcedureAuxiliary::getProcedureEquipmentId));
            List<ProcessEquipmentVO> delEquipmentList = new ArrayList<>();
            List<ProcessEquipmentVO> addEquipmentList = new ArrayList<>();
            handlerChangeTechnological(processEquipments, ObjectUtil.cloneByStream(equipmentGroupIdMap), equipmentIdAuxiliaryMap, delEquipmentList, addEquipmentList);
            processEquipments.removeAll(delEquipmentList);
            processEquipments.addAll(addEquipmentList);
        }
        return detail;
    }

    /**
     * 处理工序的变化量
     *
     * @param processEquipments       工艺工序设备数据
     * @param equipmentGroupIdMap     工序设备id对应的设备数据
     * @param equipmentIdAuxiliaryMap 工序设备id与辅助资源数据
     * @param delEquipmentList        需要删除的工艺工序设备数据
     * @param addEquipmentList        需要新增的工艺工序设备数据
     */
    private void handlerChangeTechnological(List<ProcessEquipmentVO> processEquipments,
                                            Map<Integer, WorkingProcedureEquipment> equipmentGroupIdMap,
                                            Map<Integer, List<WorkingProcedureAuxiliary>> equipmentIdAuxiliaryMap,
                                            List<ProcessEquipmentVO> delEquipmentList,
                                            List<ProcessEquipmentVO> addEquipmentList) {
        Map<Tuple2<Long, Integer>, ProcessEquipmentVO> nowProcessEquipment = MapUtil.newHashMap();
        if (MapUtil.isNotEmpty(equipmentIdAuxiliaryMap)) {
            equipmentIdAuxiliaryMap.forEach((key, value) -> {
                WorkingProcedureEquipment workingProcedureEquipment = equipmentGroupIdMap.get(key);
                for (WorkingProcedureAuxiliary workingProcedureAuxiliary : value) {
                    ProcessEquipmentVO processEquipmentVO = new ProcessEquipmentVO()
                            .setEquipmentId(workingProcedureEquipment.getEquipmentId())
                            .setEquipmentCode(workingProcedureEquipment.getEquipmentNumber())
                            .setAuxiliaryDataId(workingProcedureAuxiliary.getAuxiliaryId())
                            .setAuxiliaryDataCoding(workingProcedureAuxiliary.getAuxiliaryDataCoding());
                    nowProcessEquipment.put(Tuple.of(workingProcedureEquipment.getEquipmentId(), workingProcedureAuxiliary.getAuxiliaryId()), processEquipmentVO);
                }
                equipmentGroupIdMap.remove(key);
            });
        }

        equipmentGroupIdMap.values().forEach(equipment -> {
            ProcessEquipmentVO processEquipmentVO = new ProcessEquipmentVO()
                    .setEquipmentId(equipment.getEquipmentId())
                    .setEquipmentCode(equipment.getEquipmentNumber())
                    .setAuxiliaryDataId(null)
                    .setAuxiliaryDataCoding(null);
            nowProcessEquipment.put(Tuple.of(equipment.getEquipmentId(), null), processEquipmentVO);
        });

        Map<Tuple2<Long, Integer>, ProcessEquipmentVO> oldProcessEquipment = processEquipments.stream()
                .collect(Collectors.toMap(
                        key -> Tuple.of(key.getEquipmentId(), key.getAuxiliaryDataId()),
                        value -> value));
        Set<Tuple2<Long, Integer>> oldKeys = oldProcessEquipment.keySet();
        Set<Tuple2<Long, Integer>> nowKeys = nowProcessEquipment.keySet();
        Collection<Tuple2<Long, Integer>> del = CollUtil.subtract(oldKeys, nowKeys);
        Collection<Tuple2<Long, Integer>> add = CollUtil.subtract(nowKeys, oldKeys);
        if (CollUtil.isNotEmpty(del)) {
            del.forEach(delKey -> delEquipmentList.add(oldProcessEquipment.get(delKey)));
        }

        if (CollUtil.isNotEmpty(add)) {
            add.forEach(nowKey -> addEquipmentList.add(nowProcessEquipment.get(nowKey)));
        }


    }
}

